package com.wisecoach.gatewayplus.event;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 阻塞一个个地让监听器处理区块的分发器，默认实现
 * {@code @author:} wisecoach
 * {@code @date:} 2023/3/3 下午7:21
 * {@code @version:} 1.0.0
 */

public class BlockedFilteredBlockEventMulticaster implements FilteredBlockEventMulticaster {

    private final ProgressRecorder progressRecorder;
    private final Map<String, Set<FilteredBlockEventListener>> channelToListeners = new ConcurrentHashMap<>();

    public BlockedFilteredBlockEventMulticaster(ProgressRecorder progressRecorder) {
        this.progressRecorder = progressRecorder;
    }

    @Override
    public void addListener(String channel, FilteredBlockEventListener listener) {
        ProgressRecord record = progressRecorder.load(listener);
        listener.startAt(record.getNext());
        Set<FilteredBlockEventListener> listeners = channelToListeners.computeIfAbsent(channel, k -> new LinkedHashSet<>());
        listeners.add(listener);
    }

    @Override
    public void addListener(String channel, FilteredBlockEventListener listener, long startAt) {
        listener.startAt(startAt);
        Set<FilteredBlockEventListener> listeners = channelToListeners.computeIfAbsent(channel, k -> new LinkedHashSet<>());
        listeners.add(listener);
    }

    @Override
    public void removeListener(String channel, FilteredBlockEventListener listener) {
        Set<FilteredBlockEventListener> listeners = channelToListeners.get(channel);
        if (listeners != null) {
            listeners.remove(listener);
        }
    }

    @Override
    public void clearListener() {
        channelToListeners.clear();
    }

    @Override
    public void multicastEvent(FilteredBlockEvent event) {
        channelToListeners.get(event.getBlock().getChannelId()).forEach(listener -> invokeListener(listener, event));
    }

    private void invokeListener(FilteredBlockEventListener listener, FilteredBlockEvent event) {
        if (event.getBlock().getNumber() == listener.getNext()) {
            listener.onEvent(event);
            progressRecorder.record(listener);
        }
    }

}
